/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 
 * 系统版本: 1.0.0
 * 开发人员: zhangfb
 * 开发时间: 2019/5/31 1:06
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.aurora.mvc;


import com.hyacinth.aurora.core.ClassHelper;
import com.hyacinth.aurora.core.exception.SingleClassInstanceException;
import com.hyacinth.aurora.core.init.Initialization;
import com.hyacinth.aurora.mvc.annotation.AuroraAction;
import com.hyacinth.aurora.mvc.annotation.Mapping;
import com.hyacinth.aurora.mvc.handler.AuroraHandler;
import com.hyacinth.aurora.mvc.request.AuroraRequest;
import com.hyacinth.aurora.utils.ArrayUtil;
import com.hyacinth.aurora.utils.CollectionUtil;
import com.hyacinth.aurora.utils.StringUtil;

import javax.xml.ws.Action;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.hyacinth.aurora.constant.Constant.HttpMethod.*;

/**
 * 初始化Action配置
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class ActionHelper extends Initialization {

    /**
     * Action Map（HTTP请求与Action方法的映射）
     */
    private final Map<AuroraRequest, AuroraHandler> actionMap = new LinkedHashMap<>();

    protected ActionHelper() throws SingleClassInstanceException {
        super();
    }

    @Override
    protected void doInit() {
        // 清空缓存
        actionMap.clear();
        // 获取所有Action
        List<Class<?>> actions = ClassHelper.getClassListByAnnotation(AuroraAction.class);
        if (CollectionUtil.isNotEmpty(actions)) {
            // 定义两个ActionMap
            Map<AuroraRequest, AuroraHandler> commonActionMap = new HashMap<>(); // 存放普通 Action Map
            Map<AuroraRequest, AuroraHandler> regexpActionMap = new HashMap<>(); // 存放带有正则表达式的 Action Map
            // 遍历 Action 类
            actions.forEach(actionClass -> {
                // 获取并遍历该 Action 类中所有的方法
                Method[] actionMethods = actionClass.getDeclaredMethods();
                if (ArrayUtil.isNotEmpty(actionMethods)) {
                    for (Method actionMethod : actionMethods) {
                        // 处理 Action 方法
                        handleActionMethod(actionClass, actionMethod, commonActionMap, regexpActionMap);
                    }
                }
            });
            // 获取并遍历该 Action 类中所有的方法
            // 初始化最终的 ActionMap（将Common放在Regexp前面）
            actionMap.putAll(commonActionMap);
            actionMap.putAll(regexpActionMap);
        }
    }

    private void handleActionMethod(Class<?> actionClass,
                                    Method actionMethod,
                                    Map<AuroraRequest, AuroraHandler> commonActionMap,
                                    Map<AuroraRequest, AuroraHandler> regexpActionMap) {

        // 判断当前Action方法是否带有@Mapping注解
        if (actionMethod.isAnnotationPresent(Mapping.Get.class)) {
            String requestPath = actionMethod.getAnnotation(Mapping.Get.class).value();
            putActionMap(GET, requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } else if (actionMethod.isAnnotationPresent(Mapping.Post.class)) {
            String requestPath = actionMethod.getAnnotation(Mapping.Post.class).value();
            putActionMap(POST, requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } else if (actionMethod.isAnnotationPresent(Mapping.Put.class)) {
            String requestPath = actionMethod.getAnnotation(Mapping.Put.class).value();
            putActionMap(PUT, requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } else if (actionMethod.isAnnotationPresent(Mapping.Delete.class)) {
            String requestPath = actionMethod.getAnnotation(Mapping.Delete.class).value();
            putActionMap(DELETE, requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        }
    }

    private static void putActionMap(String requestMethod,
                                     String requestPath,
                                     Class<?> actionClass,
                                     Method actionMethod,
                                     Map<AuroraRequest, AuroraHandler> commonActionMap,
                                     Map<AuroraRequest, AuroraHandler> regexpActionMap) {
        // 判断 Request Path 中是否带有占位符
        if (requestPath.matches(".+\\{\\w+\\}.*")) {
            // 将请求路径中的占位符 {\w+} 转换为正则表达式 (\\w+)
            requestPath = StringUtil.replaceAll(requestPath, "\\{\\w+\\}", "(\\\\w+)");
            // 将 Requester 与 Handler 放入 Regexp Action Map 中
            regexpActionMap.put(new AuroraRequest(requestMethod, requestPath), new AuroraHandler(actionClass, actionMethod));
        } else {
            // 将 Requester 与 Handler 放入 Common Action Map 中
            commonActionMap.put(new AuroraRequest(requestMethod, requestPath), new AuroraHandler(actionClass, actionMethod));
        }
    }

    @Override
    protected void doDestroy() throws Exception {
        actionMap.clear();
    }

}
